/*
package cm.lunce;

import cm.lunceAnnotation.LunceIgnore;
import cm.lunceAnnotation.LunceKey;
import cm.lunceAnnotation.LunceRegister;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.DoubleDocValuesField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.queryparser.complexPhrase.ComplexPhraseQueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.springframework.aop.support.AopUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.file.Paths;
import java.text.ParseException;
import java.util.*;

*/
/**
 * @author caomin
 * @date 2017/9/14
 * @说明 工具类，自动将数据库的字段映射到Luncene中
 *//*

@Component
public class LunceneUtils {



        */
/**
         * 分页查询数据，交返回java对象
         * @param tclass 返回类型
         * @param indexDir 目录
         * @param
         * @param word 查询的单词
         * @param pageIndex 第几页
         * @param pageSize 每页的数量
         * @return
         * @throws Exception
         *//*

        public List searchData(Class tclass, String indexDir,
                               String word,
                               int pageIndex,
                               int pageSize) throws Exception {

            Set<String> keyIndexName = getKeyIndexName(tclass);
            String[] columnName = keyIndexName.toArray(new String[]{});
            List<Document> documents = this.pageSearch(indexDir, columnName, word, pageIndex, pageSize);

            return this.getSearchResult(tclass,documents);

        }

        */
/**
         * 更新索引
         *//*

        public long  updateLunce(String path,String word,Class tclass) throws IOException {
            Set<String> keyIndexName = getKeyIndexName(tclass);
             ArrayList <Term> terms=new ArrayList<>();
            for (String s : keyIndexName) {
                Term term = new Term(s, word);
                terms.add(term);
            }

            //初始化操作
            IndexWriter writer=null;
            Directory dir = FSDirectory.open(Paths.get(path));
            Analyzer analyzer = new StandardAnalyzer(); //标准分词器，会自动去掉空格啊，is a the等单词
            IndexWriterConfig config = new IndexWriterConfig(analyzer); //将标准分词器配到写索引的配置中
            writer = new IndexWriter(dir, config); //实例化写索引对象


            IndexReader reader = DirectoryReader.open(dir);
            IndexSearcher searcher = new IndexSearcher(reader);
           return writer.deleteDocuments(terms.toArray(new Term[]{}));
        }


        */
/**
         * 分页查询
         * @param indexDir
         * @param columnName
         * @param word
         * @param pageIndex
         * @param pageSize
         * @throws Exception
         *//*

        public  List<Document>  pageSearch(String indexDir,
                                           String[] columnName,
                                           String word,
                                           int pageIndex,
                                           int pageSize) throws Exception {
            Directory dir = FSDirectory.open(Paths.get(indexDir)); //获取要查询的路径，也就是索引所在的位置
            IndexReader reader = DirectoryReader.open(dir);
            IndexSearcher searcher = new IndexSearcher(reader);
            Analyzer analyzer = new StandardAnalyzer(); //标准分词器，会自动去掉空格啊，is a the等单词
            //todo 跨域搜索，在多个字段中进行搜索,暂时没用

            MultiFieldQueryParser multiFieldQueryParser=new MultiFieldQueryParser(columnName,analyzer);
            //QueryParser parser = new ComplexPhraseQueryParser(columnName,analyzer); //查询解析器

            Query query = multiFieldQueryParser.parse(word); //通过解析要查询的String，获取查询对象
            ScoreDoc[] scoreDocs = searchPageByAfter(searcher, query, pageIndex, pageSize);
            ArrayList<Document> documents = new ArrayList<>();
            for (ScoreDoc scoreDoc : scoreDocs) {
                Document doc = searcher.doc(scoreDoc.doc);
                documents.add(doc);
            }
            reader.close();
            return  documents;
        }

        */
/**
         * 数值类型默认不索引
         * @param
         * @throws IllegalAccessException
         * @throws IOException
         * @throws InstantiationException
         *//*

        public void writerData(String indexDir,List dataList) throws IllegalAccessException, IOException, InstantiationException {
            //初始化操作
            IndexWriter writer=null;
            Directory dir = FSDirectory.open(Paths.get(indexDir));
            Analyzer analyzer = new StandardAnalyzer(); //标准分词器，会自动去掉空格啊，is a the等单词
            IndexWriterConfig config = new IndexWriterConfig(analyzer); //将标准分词器配到写索引的配置中
            writer = new IndexWriter(dir, config); //实例化写索引对象

            Object dataClass = dataList.get(0);
            Class<?> sourceClass = AopUtils.getTargetClass(dataClass);
            //构建lunce中的document对象，document对象相数据库中的第一行记录
            ArrayList<Document> documents = new ArrayList(dataList.size());
            Set<String> keyIndexName = getKeyIndexName(sourceClass);
            for (Object data : dataList) {
                Document document = new Document();
                //存在多个搜索条件，转换为json字符串。存储在lunce中
                for (String key : keyIndexName) {
                    //存储整条记录
                    String jsonString = JSONObject.toJSONString(data);
                    document.add(new TextField(key,jsonString,org.apache.lucene.document.Field.Store.YES));
                }
                documents.add(document);
            }
            //写入数据
            writer.addDocuments(documents);
            writer.close();
        }

    */
/**
     * 这段代码是将Model中所有的属性作为key
     * @param sourceClass
     * @param data
     * @param document
     * @throws IllegalAccessException
     * @throws InstantiationException
     *//*

    private void setField(Class<?> sourceClass, Object data, Document document) throws IllegalAccessException, InstantiationException {
        Field[] declaredFields = sourceClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {//todo 这段代码是将Model中所有的属性作为key，和对应的值。存储在lunce中。
            declaredField.setAccessible(true);
                org.apache.lucene.document.Field convertValue=null;
                //获取值
                if (declaredField.getDeclaredAnnotation(LunceIgnore.class)==null){//要持久化
                    convertValue = getConvertValue(declaredField, data,org.apache.lucene.document.Field.Store.YES);
                }else {
                    convertValue = getConvertValue(declaredField, data,org.apache.lucene.document.Field.Store.NO);
                }
                if (convertValue==null)
                    continue;
                document.add(convertValue);
        }
    }

         */
/**
         *@Author:caomin
         *@Description: 获取类中的luncekey字段名称
         *@Date:14:38 2017/9/19
         *@parm:  * @param aClass
         *//*

        private Set<String> getKeyIndexName(Class aClass){
            Field[] declaredFields = aClass.getDeclaredFields();
            Set<String> result = new HashSet<>();
            for (Field declaredField : declaredFields) {
                LunceKey annotation = declaredField.getAnnotation(LunceKey.class);
                if (annotation !=null){
                    String name = annotation.name();
                    if (StringUtils.isEmpty(name)){
                        result.add(declaredField.getName());
                    }else {
                        result.add(name);
                    }
                }
            }
            //去LunceRegister上注解获取key主键
            LunceRegister annotation = (LunceRegister) aClass.getAnnotation(LunceRegister.class);
            if (annotation!=null){
                String[] key = annotation.key();
                if (key.length!=0){
                    for (String s : key) {
                        result.add(s);
                    }
                }
            }
            return result;
        }


        */
/**
         *
         * 通过字段类型，获取对应的lunce类型的字段
         * @param field 字段
         * @param object 对象
         * @param store 是否索引
         * @return
         * @throws IllegalAccessException
         * @throws InstantiationException
         *//*

        private org.apache.lucene.document.Field getConvertValue(Field field, Object object, org.apache.lucene.document.Field.Store  store) throws IllegalAccessException, InstantiationException {
            field.setAccessible(true);
            //lunce中的类型
            String fieldName = field.getName();
            Object fieldValue = field.get(object);
            if (fieldValue==null){
                return null;
            }
            //暂时先默认又进行存储，又建立索引
            if (fieldValue instanceof String){ //string类型
                return new TextField(fieldName, (String) fieldValue, store);
            }
            else if (fieldValue instanceof Number){ //number类型
                String longValue=null;
                if (fieldValue instanceof Integer){
                     longValue=Integer.toString((Integer) fieldValue);
                }else if (fieldValue instanceof Short){
                    longValue=Short.toString((Short) fieldValue);
                }else if (fieldValue instanceof Double){
                    longValue=Double.toString((Double) fieldValue);
                }
              Double aLong=Double.parseDouble(longValue);
                return new DoubleDocValuesField(fieldName, aLong);
            }
            else if(fieldValue instanceof Date){
                String format = DateFormatUtils.format((Date) fieldValue, "yy/MM/dd HH:mm:ss");
                return new TextField(fieldName,format, store);
            }
            else {//其余情况强转为string
                return new TextField(fieldName, (String) fieldValue, store);
            }
        }


        */
/**
         * 创建lunce
         * @param path 存放目录
         * @param list 数据
         * @throws Exception
         *//*

        public void start(String path,List list) throws Exception {
            this.writerData(path,list);
        }

        */
/**
         *不带分页
         * @param indexDir 索引目录
         * @param columnName 查询哪个列
         * @param word 查找内容
         * @throws Exception
         *//*

        public  ScoreDoc[] search(String indexDir, String columnName,String word) throws Exception {
            Directory dir = FSDirectory.open(Paths.get(indexDir)); //获取要查询的路径，也就是索引所在的位置
            IndexReader reader = DirectoryReader.open(dir);
            IndexSearcher searcher = new IndexSearcher(reader);
            Analyzer analyzer = new StandardAnalyzer(); //标准分词器，会自动去掉空格啊，is a the等单词

            //todo 跨域搜索，在多个字段中进行搜索,暂时没用
            String[] strings = new String[]{columnName};
            MultiFieldQueryParser multiFieldQueryParser=new MultiFieldQueryParser(strings,analyzer);

            QueryParser parser = new ComplexPhraseQueryParser(columnName,analyzer); //查询解析器

            Query query = parser.parse(word); //通过解析要查询的String，获取查询对象

            long startTime = System.currentTimeMillis(); //记录索引开始时间
            //获取总数量
            //int count = searcher.count(query);
            //System.out.println("查询到的总记录数"+count);
            //查询指定数量
            TopDocs docs = searcher.search(query, 100);//开始查询，查询前10条数据，将记录保存在docs中
            //分页查询？
           // TopDocs docs = searcher.searchAfter(new ScoreDoc(0,10), query, 20);
            long endTime = System.currentTimeMillis(); //记录索引结束时间
            System.out.println("匹配" + word + "共耗时" + (endTime-startTime) + "毫秒");
            System.out.println("查询到" + docs.totalHits + "条记录");
            for(ScoreDoc scoreDoc : docs.scoreDocs) { //取出每条查询结果
                Document doc = searcher.doc(scoreDoc.doc); //scoreDoc.doc相当于docID,根据这个docID来获取文档
                System.out.println(doc.get(columnName)); //fullPath是刚刚建立索引的时候我们定义的一个字段
            }
            reader.close();
            return docs.scoreDocs;
        }
        */
/**
         * 根据页码和分页大小获取上一次的最后一个scoredocs
         * @param pageIndex
         * @param pageSize
         * @param query
         * @param searcher
         * @return
         * @throws IOException
         *//*

        private ScoreDoc getLastScoreDoc(int pageIndex,int pageSize,Query query,IndexSearcher searcher) throws IOException {
            if(pageIndex==1)return null;//如果是第一页就返回空
            int num = pageSize*(pageIndex-1);//获取上一页的最后数量
            TopDocs tds = searcher.search(query, num);
            return tds.scoreDocs[num-1];
        }

        */
/**
         * 分页查询数据
         * @param searcher
         * @param query
         * @param pageIndex
         * @param pageSize
         * @return
         * @throws Exception
         *//*

        private ScoreDoc[] searchPageByAfter(IndexSearcher searcher,
                                            Query query,
                                            int pageIndex, int pageSize) throws Exception {
                //获取上一页的最后一个元素
                ScoreDoc lastSd = getLastScoreDoc(pageIndex, pageSize, query, searcher);
                //通过最后一个元素去搜索下一页的元素
                TopDocs tds = searcher.searchAfter(lastSd,query, pageSize);
               return tds.scoreDocs;
        }



        */
/**
         * 将lunce取出来的值，转换为相应java类型的值。
         * @param value
         * @param field
         * @return
         * @throws ParseException
         *//*

        private Object convertJavaType(String value,Field field) throws ParseException {
            String simpleName = field.getType().getSimpleName();
            if (simpleName.equalsIgnoreCase("date")){
                return DateUtils.parseDate(value, "yy/MM/dd HH:mm:ss");
            }
            else if (simpleName.equalsIgnoreCase("int")||simpleName.equalsIgnoreCase("integer")){
                return Integer.parseInt(value);
            }
            else if (simpleName.equalsIgnoreCase("double")){
                return Double.valueOf(value);
            }
            else if (simpleName.equalsIgnoreCase("long")){
                return Long.valueOf(value);
            }else {
                return value;
            }
        }


        */
/**
         * 将返回结果映射为java对象
         * @param tClass 要返回的对象类型
         * @param
         * @param  documents 数据源
         * @return
         * @throws Exception
         *//*

        public List  getSearchResult(Class tClass,List<Document> documents) throws Exception {
            ArrayList  result = new ArrayList<>();
            Set<String> persistentName = getPersistentName(tClass);
            for (Document document : documents) {
                Object singleResult = tClass.newInstance();
                for (String fieldName : persistentName) {
                    String value = document.get(fieldName);
                    if (StringUtils.isEmpty(value)){
                        continue;
                    }
                    //// TODO: 2017/9/20 字段名为注解上的值时，获取出错 
                    Field declaredField = tClass.getDeclaredField(fieldName);

                    declaredField.setAccessible(true);
                    //转换值
                    Object o = convertJavaType(value, declaredField);
                    declaredField.set(singleResult,o);
                }
                result.add(singleResult);
            }
            return result;
        }

        */
/**
         * 获取某个类中要做持久化和索引的字段名
         * @param clazz
         * @return
         *//*

        private Set<String>getPersistentName(Class clazz)throws  Exception{
            HashSet<String> result = new HashSet<>();
            while (!clazz.getSimpleName().equalsIgnoreCase("object")){
                Field[] declaredFields = clazz.getDeclaredFields();
                for (Field declaredField : declaredFields) {
                    LunceIgnore annotation = declaredField.getAnnotation(LunceIgnore.class);
                    if (annotation==null){
                        LunceKey key = declaredField.getAnnotation(LunceKey.class);
                        if (key!=null) {
                            String name = key.name();
                            if (!StringUtils.isEmpty(name)){
                                result.add(name);
                            }else {
                                result.add(declaredField.getName());
                            }
                        }
                    }
                }
                clazz = clazz.getSuperclass();
            }
            return result;
        }


}
*/
